/**
 * [format 字符串格式化函数]
 * @param  {[String]} args [替换的数据]
 * @return {[String]}      [格式化后的字符串]
 */
String.prototype.format = function(args) {
	var result = this;
	if (arguments.length > 0) {
		if (arguments.length == 1 && typeof(args) == "object") {
			for (var key in args) {
				if (args[key] != undefined) {
					var reg = new RegExp("({" + key + "})", "g");
					result = result.replace(reg, args[key]);
				}
			}
		} else {
			for (var i = 0; i < arguments.length; i++) {
				if (arguments[i] != undefined) {
					var reg = new RegExp("({[" + i + "]})", "g");
					result = result.replace(reg, arguments[i]);
				}
			}
		}
	}
	return result;
}

/**
 * 时间戳格式化函数
 * @param  {string} format    格式
 * @param  {int}    timestamp 要格式化的时间 默认为当前时间
 * @return {string}           格式化后的时间字符串
 */
function date(format, timestamp) {
	var jsdate = ((timestamp) ? new Date(timestamp * 1000) : new Date());
	var pad = function(n, c) {
		if ((n = n + "").length < c) {
			return new Array(++c - n.length).join("0") + n;
		} else {
			return n;
		}
	};
	var txt_weekdays = [
		"Sunday",
		"Monday",
		"Tuesday",
		"Wednesday",
		"Thursday",
		"Friday",
		"Saturday"
	];
	var txt_ordin = {
		1: "st",
		2: "nd",
		3: "rd",
		21: "st",
		22: "nd",
		23: "rd",
		31: "st"
	};
	var txt_months = [
		"",
		"January",
		"February",
		"March",
		"April",
		"May",
		"June",
		"July",
		"August",
		"September",
		"October",
		"November",
		"December"
	];
	var f = {
		// Day
		d: function() {
			return pad(f.j(), 2)
		},
		D: function() {
			return f.l().substr(0, 3)
		},
		j: function() {
			return jsdate.getDate()
		},
		l: function() {
			return txt_weekdays[f.w()]
		},
		N: function() {
			return f.w() + 1
		},
		S: function() {
			return txt_ordin[f.j()] ? txt_ordin[f.j()] : 'th'
		},
		w: function() {
			return jsdate.getDay()
		},
		z: function() {
			return (jsdate - new Date(jsdate.getFullYear() + "/1/1")) / 864e5 >> 0
		},

		// Week
		W: function() {
			var a = f.z(),
				b = 364 + f.L() - a;
			var nd2,
				nd = (new Date(jsdate.getFullYear() + "/1/1").getDay() || 7) - 1;
			if (b <= 2 && ((jsdate.getDay() || 7) - 1) <= 2 - b) {
				return 1;
			} else {
				if (a <= 2 && nd >= 4 && a >= (6 - nd)) {
					nd2 = new Date(jsdate.getFullYear() - 1 + "/12/31");
					return date("W", Math.round(nd2.getTime() / 1000));
				} else {
					return (1 + (nd <= 3 ? ((a + nd) / 7) : (a - (7 - nd)) / 7) >> 0);
				}
			}
		},

		// Month
		F: function() {
			return txt_months[f.n()]
		},
		m: function() {
			return pad(f.n(), 2)
		},
		M: function() {
			return f.F().substr(0, 3)
		},
		n: function() {
			return jsdate.getMonth() + 1
		},
		t: function() {
			var n;
			if ((n = jsdate.getMonth() + 1) == 2) {
				return 28 + f.L();
			} else {
				if (n & 1 && n < 8 || !(n & 1) && n > 7) {
					return 31;
				} else {
					return 30;
				}
			}
		},

		// Year
		L: function() {
			var y = f.Y();
			return (!(y & 3) && (y % 1e2 || !(y % 4e2))) ? 1 : 0
		},
		//o not supported yet
		Y: function() {
			return jsdate.getFullYear()
		},
		y: function() {
			return (jsdate.getFullYear() + "").slice(2)
		},

		// Time
		a: function() {
			return jsdate.getHours() > 11 ? "pm" : "am"
		},
		A: function() {
			return f.a().toUpperCase()
		},
		B: function() {
			// peter paul koch:
			var off = (jsdate.getTimezoneOffset() + 60) * 60;
			var theSeconds = (jsdate.getHours() * 3600) + (jsdate.getMinutes() * 60) + jsdate.getSeconds() + off;
			var beat = Math.floor(theSeconds / 86.4);
			if (beat > 1000)
				beat -= 1000;
			if (beat < 0)
				beat += 1000;
			if ((String(beat)).length == 1)
				beat = "00" + beat;
			if ((String(beat)).length == 2)
				beat = "0" + beat;
			return beat;
		},
		g: function() {
			return jsdate.getHours() % 12 || 12
		},
		G: function() {
			return jsdate.getHours()
		},
		h: function() {
			return pad(f.g(), 2)
		},
		H: function() {
			return pad(jsdate.getHours(), 2)
		},
		i: function() {
			return pad(jsdate.getMinutes(), 2)
		},
		s: function() {
			return pad(jsdate.getSeconds(), 2)
		},
		u: function() {
			return jsdate.getTime().toString().substr(-3)
		},
		//u not supported yet

		// Timezone
		//e not supported yet
		//I not supported yet
		O: function() {
			var t = pad(Math.abs(jsdate.getTimezoneOffset() / 60 * 100), 4);
			if (jsdate.getTimezoneOffset() > 0)
				t = "-" + t;
			else
				t = "+" + t;
			return t;
		},
		P: function() {
			var O = f.O();
			return (O.substr(0, 3) + ":" + O.substr(3, 2))
		},
		//T not supported yet
		//Z not supported yet

		// Full Date/Time
		c: function() {
			return f.Y() + "-" + f.m() + "-" + f.d() + "T" + f.h() + ":" + f.i() + ":" + f.s() + f.P()
		},
		//r not supported yet
		U: function() {
			return Math.round(jsdate.getTime() / 1000)
		}
	};

	return format.replace(/[\\]?([a-zA-Z])/g, function(t, s) {
		if (t != s) {
			// escaped
			ret = s;
		} else if (f[s]) {
			// a date function exists
			ret = f[s]();
		} else {
			// nothing special
			ret = s;
		}
		return ret;
	});
}

// 获取所有父级 id
function getParent(data, pId, config) {
	var field = { id: 'id', pId: 'pId', child: 'child' };
	if (Object.prototype.toString.call(config) === '[object Object]') {
		for (var k in config) {
			if (field.hasOwnProperty(k)) field[k] = config[k];
		}
	}

	var arrRes = [];
	if (data.length == 0) {
		if (!!pId) {
			arrRes.unshift(pId);
		}
		return arrRes;
	}
	var rev = function(arr, nodeId) {
		for (var i = 0, length = arr.length; i < length; i++) {
			var node = arr[i];
			if (node[field.id] == nodeId) {
				arrRes.unshift(nodeId);
				rev(data, node[field.pId]);
				break;
			} else {
				if (!!node[field.child]) {
					rev(node[field.child], nodeId);
				}
			}
		}
		return arrRes;
	};
	arrRes = rev(data, pId);

	return arrRes;
}

/**
 * [updateParams 过滤掉未发生变化的数据]
 * @param  {[ArrayObject]} newData [新数据]
 * @param  {[ArrayObject]} oldData [旧数据]
 * @return {[ArrayObject]}         [已变化的新数据]
 */
function updateParams(newData, oldData) {
	if (varType(newData) === 'Object' && varType(oldData) === 'Object') {
		for (var k in newData) {
			if (k !== 'id' && oldData.hasOwnProperty(k)) {
				var oldType = varType(oldData[k]);
				if (oldType === 'Number') {
					if (newData[k] !== '') newData[k] = REGEX.isInt(newData[k]) ? parseFloat(newData[k]) : '';
				}
				if (newData[k] === oldData[k] || (oldData[k] === null && newData[k] === ''))
					delete newData[k];
			}
		}
		if (Object.keys(newData).length > 0) {
			if (Object.keys(newData).length > 1 || Object.keys(newData)[0] !== 'id')
				return newData;
		}
	}
	return false;
}

var REGEX = {
	isInt: function(val){
		return /^\s*(0|[1-9]\d*)\s*$/.test(val);
	},

	isMobile: function(mobile) {
		return /^1(([38]\d)|(4[5-9])|(5[0-35-9])|66|(7[0-8])|(9[189]))\d{8}$/.test(mobile);
	},

	isEmail: function(email) {
		return /^\w+([-+.]\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*$/.test(email);
	}
};